import { fromTemplate, mergeTemplates } from '$lib/builder';
import { AI, Description, Glyph, Name } from '$lib/components';
import type { Entity, IWorld } from '$lib/ecs';
import { log } from '$lib/log';
import { getPos3, placeOnMap } from '$lib/pos3';
import { dieNormal, random, randomBetweenInclusive, randomChoice, shuffle } from '$lib/random';
import { registerAI } from '$lib/simulate';
import { notNullish } from '$lib/util';
import { Entrance, doorTemplate, entranceQuery } from './door';
import { humanTemplate } from './human';
import { drawRectangle, fillRectangle, floorTemplate, spawnNearby, spawnRandomThugs, spawnVault, spawnVaultRandom, vault } from './mapgen';
import { Mission, registerMissionTemplate } from './mission';
import { TalkNPC, registerTalkNPC } from './npc';
import { stairDownTemplate, stairUpTemplate } from './stairs';
import { bleedTrapTemplate } from './test';
import { thugTemplate } from './thug';
import { wallTemplate } from './wall';

export const newIntroMission = (world) => {
  const e = fromTemplate(world, [
    [Mission, {
      floorCount: [5, 9],
      template: 'intro',
    }]
  ]);
  return e;
};

registerMissionTemplate('intro', {
  generate: (world, floorCount, minSize, maxSize) => {
    const floors = Array.from({ length: floorCount });
    floors[floorCount-1] = bossFloor;
    floors[0] = lobbyFloor;
    for (let i = 1; i < floorCount-1; ++i) {
      floors[i] = officeFloor;
    }
    const minSizes = [...floors.map((f) => f.minSize), minSize].filter(notNullish);
    const minSide0 = Math.min(...minSizes.map((k) => k[0]));
    const minSide1 = Math.min(...minSizes.map((k) => k[1]));
    const maxSizes = [...floors.map((f) => f.maxSize), maxSize].filter(notNullish);
    const maxSide0 = Math.max(...maxSizes.map((k) => k[0]));
    const maxSide1 = Math.max(...maxSizes.map((k) => k[1]));
    console.log(minSide0, maxSide0, minSide1, maxSide1);
    const side0 = randomBetweenInclusive(minSide0, maxSide0);
    const side1 = randomBetweenInclusive(minSide1, maxSide1);
    const [width, height] = shuffle([side0, side1]);
    let stairwells = undefined;
    let x0, y0;
    for (let i = 0; i < floorCount; ++i) {
      stairwells = floors[i].generate(world, i, width, height, stairwells);
      if (i === 0) {
        // find entrance
        const entrances = entranceQuery(world);
        if (entrances.length === 0) {
          console.error("No entrance found");
          return;
        }
        const e = randomChoice(entrances);
        let {x, y} = getPos3(e);
        x0 = x;
        y0 = y;
      }
    }
    return [x0, y0, 0];
  },
  onEntrance: (world, pc) => {
    log("After losing livelihood and aimlessly wandering the streets with all but an empty pocket, you've stumbled upon a shady person who offered you a job. Full of doubts and hopes, you've arrived to the appointed building...", 'story-message');
  },
});

const lobbyFloor = {
  generate: (world, z, width, height, stairwells) => {
    if (stairwells !== undefined) {
      console.error("Lobby isn't supposed to have predefined stairwell positions!");
      return;
    }
    fillRectangle(world, floorTemplate, 0, 0, width-1, height-1, z);
    drawRectangle(world, wallTemplate, 0, 0, width-1, height-1, z);
    const [x, y] = placeEntrance(world, width, height, z);
    spawnNearby(world, introRecruiterTemplate, x, y, z);
    spawnNearby(world, thugTemplate, x, y, z);
    spawnNearby(world, bleedTrapTemplate, x, y, z);
    const result = spawnVaultRandom(world, stairwell0VaultTemplate, 1, 1, width-2, height-2, z);
    // const stairwell = stairwells[0];
    // placeMainEntrance()
    // placeBackEntrance()
    // connectRooms()
    return result;
  },
};

const placeEntrance = (world, width, height, z) => {
  const side = Math.floor(random()*4);
  let x, y;
  if (side % 2 === 0) {
    x = dieNormal(width-2, 5) + 1;
    y = Math.floor(side / 2) * (height-3) + 1;
  } else {
    y = dieNormal(height-2, 5) + 1;
    x = Math.floor(side / 2) * (width-3) + 1;
  }
  const e = fromTemplate(world, [
    [Entrance],
  ]);
  placeOnMap(world, e, x, y, z);
  return [x, y];
};

const mapping = {
  '#': wallTemplate,
  '<': stairUpTemplate,
  '>': stairDownTemplate,
  '+': doorTemplate,
};

const stairwell0VaultTemplate = vault(`
####
#< ##
#   +
#####
`, mapping, {
  toReturn: '<',
});

const stairwellVaultTemplate = vault(`
####
#<>##
#   +
#####
`, mapping, {
  toReturn: '<',
  anchor: [1, 1],
});

const introRecruiterTemplate = mergeTemplates(humanTemplate, [
  [AI],
  [Name, {
    name: 'Shady Person'
  }],
  [Description, {
    summary: "Shady Person",
    description: "A hooded figure, you can barely see their face. You think it's the same person who invited you here, but can you really be sure?",
  }],
  [TalkNPC, {
    id: 'introRecruiter',
  }],
  [Glyph, {
    color: '#24b',
  }],
]);

registerTalkNPC('introRecruiter', [
  "Hey, you punk actually showed up!",
  "Don't think you're hired yet, though.",
  "Gotta take that interview.",
  "Now don't chicken out and head up!",
]);


const bossFloor = {
  minSize: [30, 30],
  maxSize: [50, 80],
  generate: (world, z, width, height, stairwell) => {
  },
};

const officeFloor = {
  generate: (world, z, width, height, stairwell) => {
    if (stairwell === undefined) {
      console.error("Non-lobby floor should have predefined stairwell positions!");
      return;
    }
    fillRectangle(world, floorTemplate, 0, 0, width-1, height-1, z);
    drawRectangle(world, wallTemplate, 0, 0, width-1, height-1, z);
    const {x, y} = getPos3(stairwell);
    const result = spawnVault(world, stairwellVaultTemplate, x, y, z);
    spawnRandomThugs(world, z, width, height, z*8);
    return result;
  },
};
